#include <buola/gui.h>

#include <buola/xml.h>

#include "cattachmanager_private.h"

namespace buola { namespace gui {

/////////////////////// constructor and destructor /////////////////

CAttachManager::CAttachManager(const PWindow &pWindow)
    :   mWindow(pWindow)
{
    mClient=new SClient(this);
    mRoot=new SRoot(this,mClient);
}

CAttachManager::~CAttachManager()
{
    delete mRoot;
}

////////////////////////////////////////////////////////////////
//                                                            //
//                          Interface                         //
//                                                            //
////////////////////////////////////////////////////////////////

void CAttachManager::Attach(const PWindow &pChild,EAttachPlace pPlace,EAttachFlags pFlags)
{
    if(pChild->Parent()!=Window()) //reparent it here before attaching
        Window()->Place(pChild);

    Detach(pChild);

    SAttachment *lNew=new SAttachment(this,pChild,pFlags,pPlace);
    mAttachments[pChild]=lNew;

    pChild->SetFlag(CWindow::EFlags::ATTACHED);
    
    if(pPlace==ATTACH_REPLACECLIENT)
    {
        mClient->PlaceAttachment(lNew,pPlace);
    }
    else
    {
        mRoot->PlaceAttachment(lNew,pPlace);
    }
}

void CAttachManager::AttachRelative(const PWindow &pW,EAttachRelative pRel,const PWindow &pRelTo,EAttachFlags pFlags)
{
    if(pW->Parent()!=Window()) //reparent it here before attaching
        Window()->Place(pW);

    Detach(pW);


//    SAttachment *lNew=new SAttachment(this,pW,pFlags,pSize,pRel);
    SPart *lRelTo=mAttachments.count(pRelTo)?mAttachments[pRelTo]:mClient;

    msg_info() << "attaching relative to " << lRelTo << "\n";
    
    SAttachment *lNew=new SAttachment(this,pW,pFlags,lRelTo->GetDesiredPlace());
    mAttachments[pW]=lNew;

    pW->SetFlag(CWindow::EFlags::ATTACHED);
    
    lRelTo->AttachHere(lNew,pRel);
}

void CAttachManager::AttachScroll(const PWindow &pH,const PWindow &pV,EAttachPlace pPlace)
{
    Detach(pH);
    Detach(pV);

    SAttachment *lH=new SAttachment(this,pH,ATTACH_NONE,pPlace&ATTACH_HPLACES);
    mAttachments[pH]=lH;
    SAttachment *lV=new SAttachment(this,pV,ATTACH_NONE,pPlace&ATTACH_VPLACES);
    mAttachments[pV]=lV;

    pH->SetFlag(CWindow::EFlags::ATTACHED);
    pV->SetFlag(CWindow::EFlags::ATTACHED);
    
    SSplit *lOldParent=mClient->mParent;
    SScrollSplit *lSplit=new SScrollSplit(this,mClient,lH,lV);
    lOldParent->ReplaceChild(mClient,lSplit);
}

void CAttachManager::Detach(const PWindow &pWin)
{
    auto lA=mAttachments.find(pWin);
    if(lA==mAttachments.end()) return;

    lA->second->mParent->RemoveChild(lA->second);
    delete lA->second;
    mAttachments.erase(lA);

    pWin->UnsetFlag(CWindow::EFlags::ATTACHED);

    ///\todo see what this really did!
    //Window()->OnLayoutChange();
}

void CAttachManager::ResizeAttachBy(const PWindow &pWin,const CSize_d &pInc)
{
    auto lA=mAttachments.find(pWin);
    if(lA==mAttachments.end()) return;

    lA->second->ResizeBy(pInc);

    ///\todo see what this really did!
    //Window()->OnLayoutChange();
}

void CAttachManager::Undock(const PWindow &pWin)
{
    Detach(pWin);
    Window()->RemoveChild(pWin);
}

std::string CAttachManager::SaveState(SSaveHelper *pHelper)
{
    xml::CDoc lDoc;

    lDoc.Create("layout");
    mRoot->Save(lDoc.Root(),pHelper);
    return lDoc.ToString();
}

void CAttachManager::RestoreState(SSaveHelper *pHelper,const std::string &pSaved)
{
    if(pSaved.empty()) return;

    xml::CDoc lDoc;
    lDoc.Parse(pSaved);
    xml::CNode lRoot=lDoc.Root();

    mAttachments.clear();
    delete mRoot;

    for(auto lChild : lRoot.Children())
    {
        if(lChild.Name()=="root")
        {
            mRoot=new SRoot(this,lChild,pHelper);
        }
    }

    for(const auto &a : mAttachments)
    {
        if(a.second->mFlags&ATTACH_SHOW)
            a.first->Show();
    }

    ///\todo see what this really did!
    //Window()->OnLayoutChange();
}

////////////////////////////////////////////////////////////////
//                                                            //
//                          Internal                          //
//                                                            //
////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////
//                                                            //
//                      event handlers                        //
//                                                            //
////////////////////////////////////////////////////////////////

void CAttachManager::OnExpose(const CExposeEvent &pE)
{
//  CGC *lGC=pE->mGC;
}

void CAttachManager::OnChild(const PWindow &pW,int pEvent)
{
    auto lA=mAttachments.find(pW);
    if(lA==mAttachments.end()) return; //we are only interested in attached windows

    if(pEvent==CHILD_DESTROY)
    {
        Detach(pW);
    }
    else if(pEvent==CHILD_MAPPED)
    {
        ///\todo see what this really did!
        //Window()->OnLayoutChange();
    }
    else if(pEvent==CHILD_UNMAPPED)
    {
        lA->second->HideHandle();
        ///\todo see what this really did!
        //Window()->OnLayoutChange();
    }
    else if(pEvent==CHILD_TITLECHANGED)
    {
        lA->second->Redraw();
        if(lA->second->mParent->IsTabSplit())
            lA->second->mParent->Redraw();
    }
    else if(pEvent==CHILD_ACTIVATED)
    {
        if(lA->second->mParent->IsTabSplit())
            lA->second->mParent->ActivateChild(lA->second);
    }
}

void CAttachManager::OnTitleChanged()
{
    if(mRoot->mDecoration)
        mRoot->mDecoration->Refresh();
}

CRect_d CAttachManager::DoLayout()
{
    msg_info() << "doing layout for " << Window() << "\n";
    mRoot->Reshape(CRect_d({0,0},Window()->WholeSize()));
    
    msg_info() << mClient->mRect << "\n";

    return mClient->mRect;
}

/*namespace gui*/ } /*namespace buola*/ }
